# -*- coding: utf-8 -*-
from urllib import urlopen
from BeautifulSoup import BeautifulSoup
import re, codecs, string, android, time, datetime, os

droid = android.Android()


# creazione applicativo stand-alone




class ErroreFormato(Exception):
  pass


nome_giorno = """<TextView
                    android:id="@+id/box%d"
                    android:layout_width="match_parent"
                    android:layout_height="30dp"
                    android:gravity="center"
                    android:text="%s"
                    android:textColor="#ffffff"
                    android:background="#208306" 
                    android:textStyle="bold"
                    android:textSize="16dp"/>"""

bottone_orario1 = """<Button
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:text="%(testo)s"
                      android:id="@+id/%(id)s"
                      android:textSize="20dp"
                      android:textColor="#ffffffff"
                      android:gravity="center"
                      android:background="#ff66a3d2"
                      android:layout_marginRight="4dp"
                      android:layout_weight="1"/>"""
                      
bottone_orario2 = """<Button
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:text="%(testo)s"
                      android:id="@+id/%(id)s"
                      android:textSize="20dp"
                      android:textColor="#ffffffff"
                      android:gravity="center"
                      android:background="#ff66a3d2"
                      android:layout_weight="1"/>"""

testo_lezione = """<TextView
                      android:id="@+id/box%(id)d"
                      android:layout_marginLeft="4dp"
                      android:layout_marginRight="4dp"
                      android:layout_width="fill_parent"
                      android:layout_height="match_parent"
                      android:background="#fafadf"
                      android:textColor="#000000"
                      android:text="%(materia)s"
                      android:gravity="center"
                      android:layout_weight="1"/>"""

def parse(s):   #metodo parser
  giorni = ["--- Lun ---", "--- Mar ---", "--- Mer ---", "--- Gio ---", "--- Ven ---"] #inizializza hash che associa le materie ai giorni
  materie = {}
  for g in giorni:
    materie[g] = []
  # inzia il parsing 
  soup = BeautifulSoup(s)
  righe = soup.tbody.findAll('tr')
  if(len(righe)!=4):
    raise ErroreFormato
  for r in righe:
    slots = r.findAll('td')
    if(len(slots)!=6):
      raise ErroreFormato()
    for i in range(5): 
      t = slots[i+1].findAll(text=re.compile('\w'))
      if(len(t)<=0):
        raise ErroreFormato()
      if len(t)==1:
        if(t[0]!="&nbsp;"):
          raise ErroreFormato()
        materie[giorni[i]].append(t[0])
      else:
        if(len(t)%3!=0):
          raise ErroreFormato()
        materie[giorni[i]].append("%".join(t) + ";")
  output = ""    
  for g in giorni:
    output += g + "\n"
    for r in materie[g]:
      output += r + "\n"             
  return output

def selezione_dip():   #layout iniziale con lista per scegliere il corso da visualizzare      
  xml="""<?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#000000">
    <ListView
      android:id="@+id/lista_dip"
      android:layout_width="fill_parent"
      android:layout_height="match_parent"
      android:textColor="#00ff0000"
      android:layout_weight="8"/>
    <Button
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:text="Esci"
          android:id="@+id/esci"
          android:textSize="50dp"
          android:background="#ff25567b"
          android:textColor="#ffffffff"
          android:gravity="center"
          android:layout_weight="1"/>
  </LinearLayout>"""
  return xml    
    
def selezione_anno():   #layout iniziale con lista per scegliere il corso da visualizzare      
  xml="""<?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#000000">
    <ListView
      android:id="@+id/lista_anni"
      android:layout_width="fill_parent"
      android:layout_height="match_parent"
      android:textColor="#00ff0000"
      android:layout_weight="8"/>
    <LinearLayout
      android:orientation="horizontal"
      android:layout_width="fill_parent"
      android:layout_height="60dp">
    <Button
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginRight="2dp"
          android:text="Indietro"
          android:id="@+id/back"
          android:textSize="30dp"
          android:background="#ff25567b"
          android:textColor="#ffffffff"
          android:gravity="center"
          android:layout_weight="0"/>
    <Button
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Esci"
          android:id="@+id/esci"
          android:textSize="30dp"
          android:background="#ff25567b"
          android:textColor="#ffffffff"
          android:gravity="center"
          android:layout_weight="1"/>
    </LinearLayout>
  </LinearLayout>"""
  return xml
          
def selection_dip(nomidip):
  try:
    droid.fullSetList('lista_dip',nomidip)
  except:
    droid.makeToast('Impossibile caricare lista corsi')
    time.sleep(2)
    droid.makeToast('Applicazione terminata')
    time.sleep(1)
    return
  while True:
    event=droid.eventWait().result
    if event["name"]=="click": #click indica semplicemente che si sta cliccando su un bottone normale
      id=event["data"]["id"]
      if id=="esci":
        pos="esci"
        break
      elif event["name"]=="key": # esce nel caso della pressione di un tasto fuori applicazione
        pos="esci"
        break 
    # gestisce voci della lista lista_corsi    
    elif event["name"]=="itemclick": 
      pos = int(event["data"]["position"]) #memorizza posizione del click
      break
  return pos

def selection_year(nomi):   #gestisce la pressione di una zona dello schermo nel layout listato
  #names = map(lambda x:"%s" %x,nomi)
  try:
    droid.fullSetList("lista_anni",nomi) 
  except:   
    droid.makeToast('Impossibile caricare lista corsi')
    time.sleep(2)
    droid.makeToast('Applicazione terminata')
    time.sleep(1)
    return
  while True:
    event=droid.eventWait().result
    #print event
    if event["name"]=="click": #click indica semplicemente che si sta cliccando su un bottone normale
      id=event["data"]["id"]
      if id=="esci":
        pos="esci"
        break
      elif id=='back':
        pos='back'
        break
    elif event["name"]=="key":
      id = event["data"]["key"]
      if id=="4":
        pos="back"
        print pos
        break
    # gestisce voci della lista lista_corsi    
    elif event["name"]=="itemclick": 
      pos = int(event["data"]["position"]) #memorizza posizione del click
      break
  return pos
    
  
def generazione_orario(name):   #genero la tabella dell'orario del corso scelto
  i = 0
  xml='errore'
  try:
    text = codecs.open(name,mode='r',encoding='utf-8')
  except IOError:
    droid.makeToast('Impossibile reperire sorgenti!')
    time.sleep(2)
    droid.makeToast('Applicazione terminata')
    time.sleep(1)
    return xml
  except ValueError:
    droid.makeToast('Codifica sorgenti non riuscita!')
    time.sleep(2)
    droid.makeToast('Applicazione terminata')
    time.sleep(1)
    return
  #genero xml creando anche la prima colonna non contenuta nel file subject.txt
  #creo un layout orizzontale dove affianchero' i layout verticali (le colonne giorno per giorno)
  xml="""<?xml version="1.0" encoding="utf-8"?>
          <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical"
            android:background="#ffffff">
            <LinearLayout
              android:orientation="horizontal"
              android:layout_height="wrap_content"
              android:layout_width="wrap_content"
              android:baselineAligned="false"
              android:layout_weight="1">
               <LinearLayout
                android:orientation="vertical"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:background="#208306">
                <TextView
                  android:id="@+id/boxempty"
                  android:layout_width="match_parent"
                  android:layout_height="30dp"
                  android:gravity="center"
                  android:text="" />
                  <LinearLayout
                    android:orientation="vertical"
                    android:layout_weight="1">
                    <TextView
                      android:id="@+id/box0900"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="bottom"
                      android:text=" 09:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                    <TextView
                      android:id="@+id/box0110"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="top"
                      android:text=" 11:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                  </LinearLayout>
                <LinearLayout
                    android:orientation="vertical"
                    android:layout_weight="1">
                    <TextView
                      android:id="@+id/box0110"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="bottom"
                      android:text=" 11:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                    <TextView
                      android:id="@+id/box0130"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="top"
                      android:text=" 13:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                  </LinearLayout>
                <LinearLayout
                    android:orientation="vertical"
                    android:layout_weight="1">
                    <TextView
                      android:id="@+id/box0140"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="bottom"
                      android:text=" 14:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                    <TextView
                      android:id="@+id/box0160"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="top"
                      android:text=" 16:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                  </LinearLayout>
                <LinearLayout
                    android:orientation="vertical"
                    android:layout_weight="1">
                    <TextView
                      android:id="@+id/box0160"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="bottom"
                      android:text=" 16:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                    <TextView
                      android:id="@+id/box0180"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:textColor="#ffffff"
                      android:gravity="top"
                      android:text=" 18:00 "
                      android:layout_weight="1"
                      android:textStyle="bold"/>
                  </LinearLayout>
                  </LinearLayout>
                  <HorizontalScrollView 
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:layout_weight="1">
                      <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:orientation="horizontal">\n"""
  #comincio a leggere line by line dal file
  for linea in iter(text):    
    #se leggo i giorni dovro' chiudere il layout della colonna precedente
    if linea=="--- Lun ---\n" or linea=="--- Mar ---\n" or linea=="--- Mer ---\n" or linea=="--- Gio ---\n" or linea=="--- Ven ---\n":
      if linea=="--- Lun ---\n":
        xml+="""<LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:orientation="vertical">"""
      else:
        xml+="""</LinearLayout>
                <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:orientation="vertical">"""
      #creo direttamente, dopo l'inizio colonna, la textview di appoggio per il giorno
      #sostituisco i placeholder con uno dei giorni della settimana
      if linea=="--- Lun ---\n":
        xml += nome_giorno % (i,u"Lunedì")
      elif linea=="--- Mar ---\n":
        xml += nome_giorno % (i,u"Martedì")
      elif linea=="--- Mer ---\n":
        xml += nome_giorno % (i,u"Mercoledì")
      elif linea=="--- Gio ---\n":
        xml += nome_giorno % (i,u"Giovedì")
      else:
        xml += nome_giorno % (i,u"Venerdì")
      i+=1
    #se leggo not breaking-space allora creo una textview vuota
    elif linea=="&nbsp;\n":
      xml_tmp ="""<TextView
                    android:id="@+id/box%d"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="%s"
                    android:layout_weight="1"/>"""
      xml += xml_tmp % (i,"")
      i+=1
    else:
      #se infine leggo una riga con le materie creo la text view appropriata
      tmp = linea.replace(';','')
      materia=tmp.split('%')
      xml+="""<LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:layout_marginTop="4dp"
                android:layout_marginBottom="4dp"
                android:layout_weight="1">"""
      xml += testo_lezione % {"id":i,"materia":materia[0]}
      xml += testo_lezione % {"id":i,"materia":materia[1]}
      xml += testo_lezione % {"id":i,"materia":materia[2]}
      xml+="""</LinearLayout>"""
      i+=1       
  #chiusura ultima colonna e layout orizzontale delle colonne  
  xml+="""    </LinearLayout>  
          </LinearLayout>
          </HorizontalScrollView>
          </LinearLayout>"""
  #seconda parte del layout verticale principale con i bottoni in orizzontale
  xml += """    <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">"""
  xml += bottone_orario1 % {"testo":"Indietro","id":"back"} 
  xml += bottone_orario2 % {"testo":"Esci","id":"esci"}             
  xml += """    </LinearLayout>"""
  #chiusura layout schermo
  xml+="""</LinearLayout>"""
  text.close()
  return xml
  
  
def eventloop():  #gestisce la pressione di un tasto nello schermo nel layout tabellare di un corso
  while True:
     event=droid.eventWait().result
     print event
     if event["name"]=="click":  #click indica semplicemente che si sta cliccando su un bottone normale
      id=event["data"]["id"]
      if id=="esci":
        risposta="esci"
        break
      elif id=="back":
        risposta="back"
        break
     elif event["name"]=="key":   # non esce se si preme un tasto
        id=event["data"]["key"]
        if id=="4":
          risposta="back"
          print risposta
          break
  return risposta
  

def last_modification_date(filename):
    t = os.path.getmtime(filename)
    return datetime.date.fromtimestamp(t)

def main():
  corsi = {}
  dipartimenti={}
  nomi_dip=[]
  anni=[]
  nomi_corsi=[]
  indirizzi=[]
  stato=0
  
  dipartimenti['Biologia']=['Scienze biologiche LT - I Anno','Scienze biologiche LT - II Anno','Scienze biologiche LT - III Anno','Biologia LM - I Anno','Biologia LM - II Anno']
  dipartimenti['Chimica']=['Chimica LT - I Anno','Chimica LT - II Anno','Chimica LT - IIIAnno','Scienze chimiche LM - I Anno','Scienze chimiche LM - II Anno']
  dipartimenti['Fisica']=['Fisica dei sistemi complessi LM - I Anno','Fisica dei sistemi complessi LM - II Anno']
  dipartimenti['Informatica']=['Informatica LT - I Anno','Informatica LT - II Anno','Informatica LT - III Anno','Informatica LM - I Anno','Informatica LM - II Anno']
  dipartimenti['Matematica']=['Matematica LT - III Anno']
  dipartimenti['Scienze Ambientali']=['Scienze ambientali e gestione del territorio LT - I Anno','Scienze ambientali e gestione del territorio LT - II Anno','Scienze ambientali e gestione del territorio LT - III Anno']
    
  corsi['Chimica LT - I Anno'] = ('ChLT1','http://orari.disit.unipmn.it/current/cdl/4.html')
  corsi['Chimica LT - II Anno'] = ('ChLT2','http://orari.disit.unipmn.it/current/cdl/5.html')
  corsi['Chimica LT - III Anno'] = ('ChLT3','http://orari.disit.unipmn.it/current/cdl/6.html')
  corsi['Informatica LT - I Anno'] = ('InLT1','http://orari.disit.unipmn.it/current/cdl/10.html')
  corsi['Informatica LT - II Anno'] = ('InLT2','http://orari.disit.unipmn.it/current/cdl/11.html')
  corsi['Informatica LT - III Anno'] = ('InLT3','http://orari.disit.unipmn.it/current/cdl/12.html')
  corsi['Matematica LT - III Anno'] = ('MaLT3','http://orari.disit.unipmn.it/current/cdl/15.html')
  corsi['Scienze ambientali e gestione del territorio LT - I Anno'] = ('SaLT1','http://orari.disit.unipmn.it/current/cdl/16.html')
  corsi['Scienze ambientali e gestione del territorio LT - II Anno'] = ('SaLT2','http://orari.disit.unipmn.it/current/cdl/17.html')
  corsi['Scienze ambientali e gestione del territorio LT - III Anno'] = ('SaLT3','http://orari.disit.unipmn.it/current/cdl/18.html')
  corsi['Scienze biologiche LT - I Anno'] = ('BiLT1','http://orari.disit.unipmn.it/current/cdl/68.html')
  corsi['Scienze biologiche LT - II Anno'] = ('BiLT2','http://orari.disit.unipmn.it/current/cdl/75.html')
  corsi['Scienze biologiche LT - III Anno'] = ('BiLT3','http://orari.disit.unipmn.it/current/cdl/82.html')
  corsi['Biologia LM - I Anno'] = ('BiLM1','http://orari.disit.unipmn.it/current/cdl/69.html')
  corsi['Biologia LM - II Anno'] = ('BiLM2','http://orari.disit.unipmn.it/current/cdl/76.html')
  corsi['Scienze chimiche LM - I Anno'] = ('ChLM1','http://orari.disit.unipmn.it/current/cdl/70.html')
  corsi['Scienze chimiche LM - II Anno'] = ('ChLM2','http://orari.disit.unipmn.it/current/cdl/71.html')
  corsi['Informatica LM - I Anno'] = ('InLM1','http://orari.disit.unipmn.it/current/cdl/72.html')
  corsi['Informatica LM - II Anno'] = ('InLM2','http://orari.disit.unipmn.it/current/cdl/80.html')
  corsi['Fisica dei sistemi complessi LM - I Anno'] = ('FsLM1','http://orari.disit.unipmn.it/current/cdl/73.html')
  corsi['Fisica dei sistemi complessi LM - II Anno'] = ('FsLM2','http://orari.disit.unipmn.it/current/cdl/74.html')

  #assegno a 1 vettore le chiavi dell'hash dipartimenti,ordinate alfabeticamente
  nomi_dip=dipartimenti.keys()
  nomi_dip.sort()
  for i in nomi_dip:
    anni.append(dipartimenti[i])
  #assegno ai 2 vettori chiave e valore dell'hash corsi, ordinati alfabeticamente
  nomi_corsi=corsi.keys()
  nomi_corsi.sort()
  for i in nomi_corsi:
    indirizzi.append(corsi[i][1])
  while True:
    nomefile='/sdcard/sl4a/scripts/'
    off=0
    modifica="E' possibile vedere la tabella aggiornata al "
    if stato==0:
      dip=selezione_dip()
      droid.fullShow(dip)
      sel=selection_dip(nomi_dip)
      if sel=='esci':
        break
      mydip=anni[sel]
    stato=0
    lista=selezione_anno()
    #droid.addOptionsMenuItem("Silly","silly",None,"star_on") 
    droid.fullShow(lista)
    myear=selection_year(mydip)   #selezione corso desiderato
    if myear=="esci":
      break
    elif myear=='back':
      continue
    nome=dipartimenti[nomi_dip[sel]][myear]
    print nome
    myurl=corsi[nome][1]
    print myurl
    nomefile += corsi[nome][0]
    print nomefile
    try:
      page = urlopen(myurl) #apertura url
      html = page.read()
      page.close()
      try:
        out = parse(html)  #inizio parsing
      except ErroreFormato:
        droid.makeToast('Formato HTML non riconosciuto')
        time.sleep(1)
        droid.makeToast('Applicazione terminata!')
        time.sleep(1)
        break
    except (ValueError, IOError):
      off=1
    print off
    if off==0:
      outfile = codecs.open(nomefile,mode='w',encoding='utf-8')
      outfile.write(out)
      outfile.close()
    else:
      try:
        outfile = codecs.open(nomefile,mode='r',encoding='utf-8')
        outfile.close()
        last = last_modification_date(nomefile)
        modifica += last.isoformat() + ". Continuare?"
        droid.dialogCreateAlert("Impossibile connettersi alla rete!", modifica )
        droid.dialogSetNegativeButtonText('Continua')
        droid.dialogSetPositiveButtonText('Indietro')
        droid.dialogShow()  
        r =  droid.dialogGetResponse().result
        if r['which']=='positive':
          stato=1
          continue
      except IOError:
        droid.dialogCreateAlert("Impossibile reperire i sorgenti!" )
        droid.dialogSetNegativeButtonText('Continua')
        droid.dialogSetPositiveButtonText('Esci')
        droid.dialogShow()  
        r =  droid.dialogGetResponse().result
        if r['which']=='positive':
          break
        elif r['which']=='negative':
          continue
    droid.makeToast('Attendere...')
    layout=generazione_orario(nomefile)  #generazione della stringa xml
    if layout=='errore':
      break
    droid.fullShow(layout) #visualizza layout xml
    risp=eventloop()  #azioni quando si visualizza la tabella
    if risp=="esci":
      break
    else:
      stato=1
      continue
  droid.fullDismiss()
  return
   
main()
